
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Hashtable;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

public class XMLPacketParser extends DefaultHandler{

	ArrayList<Packet> packetHeader;
	ArrayList<Packet> videoTraffic;
	Packet pckt;
	ArrayList <String> sessions;
	ArrayList <String> videoPorts;
	boolean start = true;
	int counter = 0;
	Hashtable videoSession;
	//private String tempVal;

	//to maintain context
	int packetCounter =0 ;




	public void runExample() {
		parseDocument();
		printData();
		analyzeSessions();
		printSessionInformation();
		analyzeVideoPacketStream();
		
		

	}

	private void analyzeVideoPacketStream() {
		// TODO Auto-generated method stub
		java.util.HashMap< String, java.util.Vector<Packet>> history= 
			new java.util.HashMap<String, java.util.Vector<Packet>>();
		
		for (int i = 0; i< videoTraffic.size() ; i++)
		{
			Packet pck = videoTraffic.get(i);
			String unique_comm = pck.getSrcIPAddr()+"_"+pck.getDestIPAddr();
			
		    if (history.containsKey(unique_comm) ) {
			   if ( pck.isMarker() ) // means one tranmission is finsihed
			    {
			      //do the final bits.. 	
			      //it means we hv infor abt this src n dest n ew hv reached the marker
				   java.util.Vector<Packet> old = (java.util.Vector<Packet>)history.get(unique_comm);
					old.add(pck);
					//history.put(unique_comm, old);
					//now what if we encounter another stream for same src_dest...
					///needs some changes here
			        //we need to process it right here.. n then empty it again
					this.showSomething(old);
					//one it is done, empty this key-value mapping
					history.remove(unique_comm);
				}
				else{
					//append new packet in the old thread
				    java.util.Vector old = history.get(unique_comm);
				    old.add(pck);
				    //update history for this src n dest
				    history.put(unique_comm, old);
				}
			}
		    else{
		    	
		    }
		}
		
	}

	public void showSomething(java.util.Vector<Packet> pckts){
		for( Packet pk : pckts){
			System.out.println(pk.getArrivalTime());
		}
	}
	
	private void printSessionInformation() {
		// TODO Auto-generated method stub
		 Enumeration e = videoSession.keys();
	       
	        while( e. hasMoreElements() ){ 
	        	String session = (String) e.nextElement();
	            System.out.println("Session : "  + session + " Packets in that session " + videoSession.get(session));
	        }
		
	}


	
	public void analyzeSessions()
	{
		int next = 0;
		try{
			for (int i =0; i < videoTraffic.size() ; i++)
			{
				Packet pack = videoTraffic.get(i);

				if (pack.getSession()!=null)
				{
					if(videoSession.isEmpty())
					{
						videoSession.put((String) pack.getSession(), 1);
						System.out.println("Video Frame Starting from : " + pack.getFrameNumber());

					}
					//System.out.println("Packet session key " + pack.getSession());
					else if (videoSession.containsKey((String) pack.getSession()))
					{
						int value = ((Integer) ( videoSession.get((String)pack.getSession()))).intValue();
						value++;
						//System.out.println("Video Session Found!!");
						videoSession.put((String) pack.getSession(), value);
						if (next < 10)
						{
							System.out.println("Video Frame Starting from : " + pack.getFrameNumber());
							next ++;
						}

					}
					else
					{
						videoSession.put((String) pack.getSession(), 1);

					}
				}
				else
				{
					System.out.println(pack.getFrameNumber());
				}
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

	}

	private void parseDocument() {

		//get a factory
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {

			//get a new instance of parser
			SAXParser sp = spf.newSAXParser();

			//parse the file and also register this class for call backs
			sp.parse("../file/telepresemce-full-xml.xml", this);

		}catch(SAXException se) {
			se.printStackTrace();
		}catch(ParserConfigurationException pce) {
			pce.printStackTrace();
		}catch (IOException ie) {
			ie.printStackTrace();
		}
	}

	/**
	 * Iterate through the list and print
	 * the contents
	 */
	private void printData(){

		try{
			System.out.println("No of Packets '" + packetHeader.size() + "'.");


			Iterator<Packet> it = packetHeader.iterator();
			FileWriter fstream = new FileWriter("ip-tv.txt");
			BufferedWriter out = new BufferedWriter(fstream);
			int stopCounter = 0;
			while(it.hasNext()) {
				Packet header = (Packet)it.next();
				if(header.getSession() != null)
					if (start )
					{

						sessions.add(header.getSession());
						System.out.println("Session " + header.getSession());
						start = false;
					}
					else{
						if (sessions.contains((String)header.getSession()))
						{
							//	System.out.println("Match");
						}
						else
						{
							System.out.println(header.getSession());
							sessions.add(header.getSession());
						}
					}


				//if(stopCounter < 5)
				{
					// Create file 
					out.write(header.frameNumber + "\t" + header.frame_Length +"\t" +  header.arrivalTime + "\t" + header.getDelta_from_previous_captured().toString()
							+ "\t" + header.getDelta_from_previous_displayed().toString()+ "\t" + header.getTime_since_first().toString()+ "\n");
					//Close the output stream


					//System.out.println(header.frameNumber + "\t" + header.frame_Length +"\t" +  header.arrivalTime + "\t" + header.getDelta_from_previous_captured().toString()
					//	+ "\t" + header.getDelta_from_previous_displayed().toString()+ "\t" + header.getTime_since_first().toString());
					stopCounter++;
				}
				/*	else
				{
					break;
				}*/
			}
			out.flush();
			out.close();
			fstream.close();

		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}
	}


	//Event Handlers
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		//reset
		//	tempVal = "";



		//Extracting frame number and size
		if(qName.equalsIgnoreCase("proto")) {

			for (int attr=0; attr < attributes.getLength(); attr++)
			{
				if (attributes.getQName(attr).equalsIgnoreCase("showname")  && attributes.getValue(attr).startsWith("Internet"))
				{
					//System.out.println( attributes.getValue(attr));
					String ipAddr[]  =  attributes.getValue(attr).split(",");
					pckt.setSrcIPAddr((ipAddr[1].substring(ipAddr[1].indexOf(":")+1, ipAddr[1].indexOf("("))).trim());
					pckt.setDestIPAddr((ipAddr[2].substring(ipAddr[2].indexOf(":")+1 , ipAddr[2].indexOf("("))).trim());
					//System.out.println((ipAddr[1].substring(ipAddr[1].indexOf(":")+1, ipAddr[1].indexOf("("))).trim());
					//System.out.println((ipAddr[2].substring(ipAddr[2].indexOf(":")+1 , ipAddr[2].indexOf("("))).trim());
				}

				if (attributes.getQName(attr).equalsIgnoreCase("showname") && attributes.getValue(attr).startsWith("Frame"))
				{
					//System.out.println(attributes.getQName(attr) + "  " +" %% " + attributes.getValue(attr));
					String packetHeaderValue [] =  attributes.getValue(attr).split(" ");
					packetHeaderValue[2].trim();
					//System.out.println(packetHeaderValue[2].replaceAll("\\(", ""));
					String totalBytes [] = packetHeaderValue[2].split("\\(");//removing right hand bracket
					//	System.out.println(packetHeaderValue[0] + " " 
					//	+ packetHeaderValue[1] + " " +  totalBytes [1]);
					pckt.frameNumber = packetHeaderValue[1];
					pckt.setFrameNumber(packetHeaderValue[1]);
					pckt.frame_Length = Long.parseLong(totalBytes [1].trim());

				}


			}

		}

		//Extracting time  information 
		if(qName.equalsIgnoreCase("field")) {

			for (int attr=0; attr < attributes.getLength(); attr++)
			{
				//System.out.println(attributes.getQName(attr) + "  " +" %% " + attributes.getValue(attr));


				if (attributes.getQName(attr).equalsIgnoreCase("showname"))
				{
					if( attributes.getValue(attr).contains("Arrival Time"))
					{
						//System.out.println(attributes.getQName(attr) + "  " +" %% " + attributes.getValue(attr));
						/* Arrival Time: May 23, 2008 14:19:12.497542000
						 * Assuming that the communication is happening in seconds only
						 * we are only interested in the last field that is seconds
						 */

						String arrivalTime [] =  attributes.getValue(attr).split(":");
						pckt.arrivalTime = arrivalTime[(arrivalTime.length-1)];
						//System.out.println("Arrival time in seconds : " + arrivalTime[(arrivalTime.length-1)]);



					}
					if( attributes.getValue(attr).contains("Time delta"))
					{
						//System.out.println(attributes.getQName(attr) + "  " +" %% " + attributes.getValue(attr));
						String timeDelta [] =  attributes.getValue(attr).split(":");

						//Time delta from previous captured frame: 0.000086000 seconds
						if(timeDelta[0].contains("captured"))
						{
							// Parse string to get time 0.000086000 seconds
							String timeOnly [] = timeDelta[1].split("\\s+");
							//System.out.println("Captured time " + timeOnly[1]);
							pckt.setDelta_from_previous_captured(new BigDecimal(timeOnly[1]));
							//pckt.delta_from_previous_captured = Float.parseFloat(timeOnly[1]);


						}
						//Time delta from previous displayed frame: 0.000086000 seconds
						if(timeDelta[0].contains("displayed"))
						{
							String timeOnly [] = timeDelta[1].split("\\s+");
							//System.out.println("Displayed time " + timeOnly[1]);
							pckt.setDelta_from_previous_displayed(new BigDecimal(timeOnly[1]));


						}



					}
					//Time since reference or first frame: 22.038315000 seconds
					if (attributes.getValue(attr).contains("Time since"))
					{
						String timeDelta [] =  attributes.getValue(attr).split(":");
						String timeOnly [] = timeDelta[1].split("\\s+");
						//System.out.println("First " + timeOnly[1]);
						pckt.setTime_since_first(new BigDecimal(timeOnly[1]));



						//System.out.println(attributes.getQName(attr) + "  " +" %% " + attributes.getValue(attr));


					}

					if (attributes.getQName(attr).equalsIgnoreCase("showname") && attributes.getValue(attr).startsWith("Synchronization Source identifier"))
					{
						String stream []  = attributes.getValue(attr).split("\\(");
						String newStream = stream[1].substring(0, stream[1].length() -1);
						//System.out.println (newStream);
						pckt.session = newStream ; 
					}

					if (attributes.getQName(attr).equalsIgnoreCase("showname") && attributes.getValue(attr).startsWith("Media Description"))
					{
						String tempPorts [] = attributes.getValue(attr).split("\\:");
						tempPorts[1].trim();
						String tPorts    [] = tempPorts[1].split("\\s+");
						//System.out.println(tPorts[1] + " " + tPorts[2]  );
						if (tPorts[1].equals("video"))
							videoPorts.add(tPorts[2]);
						//System.out.println(attributes.getValue(attr));
					}

					if (attributes.getQName(attr).equalsIgnoreCase("showname") && attributes.getValue(attr).startsWith("Source port"))
					{
						String tempSrcPort []  = attributes.getValue(attr).split("\\(");
						String srcPort = tempSrcPort[1].substring(0, tempSrcPort[1].length() -1);

						//System.out.println("Src Port " + srcPort);
						pckt.setSrcPort(srcPort);
					}
					if (attributes.getQName(attr).equalsIgnoreCase("showname") && attributes.getValue(attr).startsWith("Destination port"))
					{
						String tempDestPort []  = attributes.getValue(attr).split("\\(");
						String destPort = tempDestPort[1].substring(0, tempDestPort[1].length() -1);

						//System.out.println("Dest Port " + destPort);
						pckt.setDestPort(destPort);
						if (videoPorts.contains((String) destPort))
						{
							//System.out.println("Port found" + destPort);
							pckt.setVideoPacket(true);
							//counter++;
						}
					}
					
				// Checking for the value of Marker
					if(attributes.getQName(attr).equalsIgnoreCase("showname") && attributes.getValue(attr).contains("Marker"))
					{
						//System.out.println (attributes.getValue(attr));
						//0... .... = Marker: False
						String markerValue = attributes.getValue(attr).substring(attributes.getValue(attr).indexOf(":")+1,attributes.getValue(attr).length());
						markerValue = markerValue.trim();
						
						if(markerValue.equals("True"))
						{
							pckt.setMarker(true);
							//System.out.println(pckt.getFrameNumber() + "  "  + markerValue);
							
						}
						else
						{
							pckt.setMarker(false);
							//System.out.println(pckt.getFrameNumber() + "  "  + markerValue);
						}
						
						
					}






				}
			}

		}


		if(qName.equalsIgnoreCase("Packet")) {
			this.packetCounter++;

			//create a new instance of employee
			//System.out.println("Packet Count " + packetCounter );
			pckt = new Packet();

		}
	}


	public void characters(char[] ch, int start, int length) throws SAXException {
		//	tempVal = new String(ch,start,length);

	}

	public void endElement(String uri, String localName, String qName) throws SAXException {

		if(qName.equalsIgnoreCase("Packet")) {
			//add it to the list
			packetHeader.add((Packet) pckt);
			if(pckt.isVideoPacket())
			{
				videoTraffic.add((Packet)pckt);
			}

		}else if (qName.equalsIgnoreCase("getinfo")) {
			System.out.println("Getinf foud asd=fasdfjkl; va");
		}
		else if(qName.equalsIgnoreCase("proto")) {
			//	System.out.println("");
		}

	}

	public XMLPacketParser() {
		packetHeader = new ArrayList<Packet>();
		sessions     = new ArrayList<String>();
		videoPorts   = new ArrayList<String>();
		videoTraffic = new ArrayList<Packet>();
		videoSession =  new Hashtable();
	}

	public static void main(String[] args){
		XMLPacketParser spe = new XMLPacketParser();
		spe.runExample();
		System.out.println("Counter : " + spe.counter);
	}

}



